{"componentChunkName":"component---node-modules-gatsby-theme-chronoblog-src-templates-post-js","path":"/nightwatch-typescript-custom-command-extensibility/","result":{"data":{"mdx":{"id":"ac2df9c1-2c46-50ff-8fcc-94118039b97a","excerpt":"It's been about a year since my last post about  using Nightwatch test automation with TypeScript  (instead of the JavaScript default). The…","frontmatter":{"title":"Adding Custom Commands to Nightwatch TypeScript Projects","date":"2023-04-21T00:00:00.000Z","description":"Learn how to extend Nightwatch's built-in automation commands with your own when working inside a TypeScript Nightwatch test project in this post.","tags":["quality assurance","software testing","nightwatchjs","typescript","nightwatch","post"],"cover":{"childImageSharp":{"fluid":{"base64":"data:image/jpeg;base64,/9j/2wBDAAMCAgMCAgMDAwMEAwMEBQgFBQQEBQoHBwYIDAoMDAsKCwsNDhIQDQ4RDgsLEBYQERMUFRUVDA8XGBYUGBIUFRT/2wBDAQMEBAUEBQkFBQkUDQsNFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBT/wgARCAANABQDASIAAhEBAxEB/8QAFwAAAwEAAAAAAAAAAAAAAAAAAAYHBP/EABUBAQEAAAAAAAAAAAAAAAAAAAMA/9oADAMBAAIQAxAAAAHfOKqirJAyCD//xAAbEAACAgMBAAAAAAAAAAAAAAAEBQEDAgYTFf/aAAgBAQABBQIrW/MHGnNiW1XWK2GwMrKS6iuJbXODyf/EABoRAAICAwAAAAAAAAAAAAAAAAECAAMEESH/2gAIAQMBAT8BORao2YHZugT/xAAZEQACAwEAAAAAAAAAAAAAAAABAgADIRL/2gAIAQIBAT8BWmtjyMhrRcJn/8QAIBAAAgIBBQADAAAAAAAAAAAAAQIDEQAEEhMhMSIyUf/aAAgBAQAGPwKZY1bUOyduihV3ZDAIk+TcYZgaHeTaWSmeM9lfMlg05eEJ9jyE7sEhjRivtDbeCWuM7ADRuz+5/8QAHBABAAIDAQEBAAAAAAAAAAAAAREhADFBUWGx/9oACAEBAAE/IWeWoBGqWfbwZOBSdhz7+46EIA2ie+axwljL58ugvUYlySBhmxjJ9YgD0WO5/9oADAMBAAIAAwAAABDQz//EABsRAAIBBQAAAAAAAAAAAAAAAAERACFBYdHh/9oACAEDAQE/EDFZVkNQFSg55P/EABoRAQACAwEAAAAAAAAAAAAAAAEAEUFh0eH/2gAIAQIBAT8QFo2zb2IXVNez/8QAGxABAQEBAQEBAQAAAAAAAAAAAREhAEExYXH/2gAIAQEAAT8QSs/CalUj1RB5trmZFLeVP7wUMD6gQfWlX6O8zUwJjSHPX2vrM5XSFGdRZFLUUdE4dHDwCtKimpu+9//Z","aspectRatio":1.5,"src":"/static/22b9dc1f84ca47e09e6eec3207ccb83d/3e61c/nightwatch-typescript-article-banner.jpg","srcSet":"/static/22b9dc1f84ca47e09e6eec3207ccb83d/7fcb3/nightwatch-typescript-article-banner.jpg 192w,\n/static/22b9dc1f84ca47e09e6eec3207ccb83d/42594/nightwatch-typescript-article-banner.jpg 384w,\n/static/22b9dc1f84ca47e09e6eec3207ccb83d/3e61c/nightwatch-typescript-article-banner.jpg 768w","srcWebp":"/static/22b9dc1f84ca47e09e6eec3207ccb83d/dd090/nightwatch-typescript-article-banner.webp","srcSetWebp":"/static/22b9dc1f84ca47e09e6eec3207ccb83d/ae504/nightwatch-typescript-article-banner.webp 192w,\n/static/22b9dc1f84ca47e09e6eec3207ccb83d/fef30/nightwatch-typescript-article-banner.webp 384w,\n/static/22b9dc1f84ca47e09e6eec3207ccb83d/dd090/nightwatch-typescript-article-banner.webp 768w","sizes":"(max-width: 768px) 100vw, 768px","presentationWidth":768,"presentationHeight":512},"resize":{"src":"/static/22b9dc1f84ca47e09e6eec3207ccb83d/3e61c/nightwatch-typescript-article-banner.jpg"}}}},"fields":{"slug":"/nightwatch-typescript-custom-command-extensibility/"},"body":"var _excluded = [\"components\"];\nfunction _extends() { _extends = Object.assign ? Object.assign.bind() : function (target) { for (var i = 1; i < arguments.length; i++) { var source = arguments[i]; for (var key in source) { if (Object.prototype.hasOwnProperty.call(source, key)) { target[key] = source[key]; } } } return target; }; return _extends.apply(this, arguments); }\nfunction _objectWithoutProperties(source, excluded) { if (source == null) return {}; var target = _objectWithoutPropertiesLoose(source, excluded); var key, i; if (Object.getOwnPropertySymbols) { var sourceSymbolKeys = Object.getOwnPropertySymbols(source); for (i = 0; i < sourceSymbolKeys.length; i++) { key = sourceSymbolKeys[i]; if (excluded.indexOf(key) >= 0) continue; if (!Object.prototype.propertyIsEnumerable.call(source, key)) continue; target[key] = source[key]; } } return target; }\nfunction _objectWithoutPropertiesLoose(source, excluded) { if (source == null) return {}; var target = {}; var sourceKeys = Object.keys(source); var key, i; for (i = 0; i < sourceKeys.length; i++) { key = sourceKeys[i]; if (excluded.indexOf(key) >= 0) continue; target[key] = source[key]; } return target; }\n/* @jsxRuntime classic */\n/* @jsx mdx */\n\nvar _frontmatter = {\n  \"title\": \"Adding Custom Commands to Nightwatch TypeScript Projects\",\n  \"cover\": \"./nightwatch-typescript-article-banner.jpg\",\n  \"date\": \"2023-04-21T00:00:00.000Z\",\n  \"description\": \"Learn how to extend Nightwatch's built-in automation commands with your own when working inside a TypeScript Nightwatch test project in this post.\",\n  \"tags\": [\"quality assurance\", \"software testing\", \"nightwatchjs\", \"typescript\", \"nightwatch\", \"post\"]\n};\nvar makeShortcode = function makeShortcode(name) {\n  return function MDXDefaultShortcode(props) {\n    console.warn(\"Component \" + name + \" was not imported, exported, or provided by MDXProvider as global scope\");\n    return mdx(\"div\", props);\n  };\n};\nvar Embed = makeShortcode(\"Embed\");\nvar layoutProps = {\n  _frontmatter: _frontmatter\n};\nvar MDXLayout = \"wrapper\";\nreturn function MDXContent(_ref) {\n  var components = _ref.components,\n    props = _objectWithoutProperties(_ref, _excluded);\n  return mdx(MDXLayout, _extends({}, layoutProps, props, {\n    components: components,\n    mdxType: \"MDXLayout\"\n  }), mdx(\"p\", null, \"It's been about a year since my last post about \", mdx(\"a\", {\n    parentName: \"p\",\n    \"href\": \"../using-nightwatch-with-typescript/\"\n  }, \"using Nightwatch test automation with TypeScript\"), \" (instead of the JavaScript default). The Nightwatch developers have added significant features in that time making it even more convenient to get the benefits of TypeScript when working in Nightwatch Test Automation.\"), mdx(\"p\", null, \"This post will cover adding custom commands, one of the less documented areas, when working in a TypeScript Nightwatch project rather than a JS one. This is a bit trickier than when working in JavaScript because JavaScript has no type-checking whereas TypeScript does so one needs to append any custom commands not part of the Nightwatch API to the type definitions.\"), mdx(\"p\", null, \"In addition, this article will serve as an update to the original Nightwatch TypeScript how-to post with some of convenient new updates since the article was written. For example,\"), mdx(\"ul\", null, mdx(\"li\", {\n    parentName: \"ul\"\n  }, \"Automatic project scaffolding\"), mdx(\"li\", {\n    parentName: \"ul\"\n  }, \"Execution of .ts tests without requiring \", mdx(\"inlineCode\", {\n    parentName: \"li\"\n  }, \"tsc\"), \" transpiling first.\")), mdx(\"h2\", {\n    \"id\": \"creating-a-typescript-nightwatch-test-suite-with-npm-init\"\n  }, \"Creating a TypeScript Nightwatch Test Suite (with npm init)\"), mdx(\"p\", null, \"One can now do a \\\"choose-your-own-adventure\\\" type of project setup when creating new Nightwatch projects through their scaffolding command \", mdx(\"inlineCode\", {\n    parentName: \"p\"\n  }, \"npm init nightwatch@latest\"), \". Where one can answer what kind of test project they want to create, which browsers to run on, and if they are doing so using a cloud test provider like SauceLabs or  BrowserStack. Everything is automatically downloaded and configured, including the nightwatch.conf.js file, to their selections.\"), mdx(\"p\", null, \"Here is an example of it getting a new \", mdx(\"a\", {\n    parentName: \"p\",\n    \"href\": \"https://www.youtube.com/shorts/IJ_nBsPLslo\"\n  }, \"TypeScript project setup from scratch in under 60 seconds\"), \".\"), mdx(Embed, {\n    src: \"https://www.youtube.com/embed/IJ_nBsPLslo\",\n    mdxType: \"Embed\"\n  }), mdx(\"p\", null, \"Steps\"), mdx(\"ol\", null, mdx(\"li\", {\n    parentName: \"ol\"\n  }, \"At a command line type \", mdx(\"inlineCode\", {\n    parentName: \"li\"\n  }, \"npm init nightwatch@latest\")), mdx(\"li\", {\n    parentName: \"ol\"\n  }, \"Affirmatively answer to proceed.\"), mdx(\"li\", {\n    parentName: \"ol\"\n  }, \"Select TypeScript\")), mdx(\"pre\", null, mdx(\"code\", {\n    parentName: \"pre\",\n    \"className\": \"language-sh\"\n  }, \"===============================\\nNightwatch Configuration Wizard\\n===============================\\n\\nSetting up Nightwatch in C:\\\\test-automation\\\\nightwatch-typescript...\\n\\n? Select testing type to setup for your project End-to-End testing\\n? Select language + test runner variant \\n  JavaScript / default\\n> TypeScript / default\\n  JavaScript / Mocha\\n  JavaScript / CucumberJS\\n\")), mdx(\"p\", null, \"Differing from my earlier article, the new recommended project structure has all the tests, page objects, custom commands, and so on under the \", mdx(\"inlineCode\", {\n    parentName: \"p\"\n  }, \"/nightwatch\"), \" folder.\"), mdx(\"pre\", null, mdx(\"code\", {\n    parentName: \"pre\"\n  }, \"nightwatch.config.js\\n/nightwatch\\n\\u2514\\u2500\\u2500\\u2500tsconfig.json\\n\\u2502\\n\\u2514\\u2500\\u2500\\u2500/page-objects\\n\\u2502   \\u2502\\n\\u2502   \\u2514\\u2500\\u2500\\u2500testPage1.ts\\n\\u2502   \\u2514\\u2500\\u2500\\u2500testPage2.ts\\n\\u2502\\n\\u2514\\u2500\\u2500\\u2500/tests\\n\\u2502   \\u2502\\n\\u2502   \\u2514\\u2500\\u2500\\u2500test1.ts\\n\\u2502   \\u2514\\u2500\\u2500\\u2500test2.ts\\n\\u2502\\n\\u2514\\u2500\\u2500\\u2500/commands\\n\\u2502   \\u2502\\n\\u2502   \\u2514\\u2500\\u2500\\u2500customWait.ts\\n\\u2502\\n\\u2514\\u2500\\u2500\\u2500/types\\n    \\u2502\\n    nightwatch.d.ts\\n\\n\")), mdx(\"p\", null, \"Default sample tests are included and don't need to be transpiled with \", mdx(\"inlineCode\", {\n    parentName: \"p\"\n  }, \"tsc\"), \" to JavaScript before running. To execute tests when setup in this project structure you can simply run \", mdx(\"inlineCode\", {\n    parentName: \"p\"\n  }, \"npx nightwatch\"), \" to run all your tests or \", mdx(\"inlineCode\", {\n    parentName: \"p\"\n  }, \"npx nightwatch -t ./nightwatch/tests/your-test-here.ts\"), \" for a specific test.\"), mdx(\"h2\", {\n    \"id\": \"writing-custom-commands-in-a-nightwatch-typescript-project\"\n  }, \"Writing Custom Commands in a Nightwatch TypeScript project\"), mdx(\"p\", null, \"One of the nice features about Nightwatch is how easy it is to extend the API with ones own custom commands. Commands in the directory that one adds in the path of their \", mdx(\"inlineCode\", {\n    parentName: \"p\"\n  }, \"custom_commands_path\"), \" property of \", mdx(\"inlineCode\", {\n    parentName: \"p\"\n  }, \"nightwatch.conf.js\"), \" will automatically be available on the \", mdx(\"inlineCode\", {\n    parentName: \"p\"\n  }, \"browser\"), \" object as \", mdx(\"inlineCode\", {\n    parentName: \"p\"\n  }, \"browser.yourCommandHere()\"), \" when writing their tests. This takes advantage of the fact JavaScript doesn't do type checking. However, TypeScript is more structured in that it does type-checking which creates a conflict here since \\\"yourCommand\\\" is not part of \", mdx(\"a\", {\n    parentName: \"p\",\n    \"href\": \"https://www.npmjs.com/package/@types/nightwatch\"\n  }, \"@types/nightwatch\"), \" so TypeScript alerts that the command does not exist. To correct this, one can leverage an overriding definition file like \", mdx(\"inlineCode\", {\n    parentName: \"p\"\n  }, \"nightwatch.d.ts\"), \" that would append the custom command to the existing Nightwatch types.\"), mdx(\"h3\", {\n    \"id\": \"step-1-create-your-custom-command\"\n  }, \"Step 1: Create your custom command\"), mdx(\"p\", null, \"The structure is very similar to the existing \", mdx(\"a\", {\n    parentName: \"p\",\n    \"href\": \"https://nightwatchjs.org/guide/extending-nightwatch/adding-custom-commands.html#guide-container\"\n  }, \"custom command documentation\"), \", but adds some types as shown in this simple example\"), mdx(\"pre\", null, mdx(\"code\", {\n    parentName: \"pre\",\n    \"className\": \"language-ts\"\n  }, \"// nightwatch/commands/waitForLoadScreen.ts\\nimport { NightwatchCLient, NightwatchExpectedResult } from 'nightwatch'\\n\\nexport default class WaitForLoadScreen {\\n  async command(\\n    this: NightwatchClient,\\n    maxWaitInMs: number\\n  ): Promise<NightwatchExpectResult> {\\n    return this.api.expect\\n      .element('#loadScreenOverlay')\\n      .to.not.be.visible.before(maxWaitInMs);\\n  }\\n}\\n\")), mdx(\"p\", null, \"This file should be stored in the \", mdx(\"inlineCode\", {\n    parentName: \"p\"\n  }, \"./nightwatch/commands\"), \" folder with \", mdx(\"inlineCode\", {\n    parentName: \"p\"\n  }, \"nightwatch.conf.js\"), \" set to\"), mdx(\"pre\", null, mdx(\"code\", {\n    parentName: \"pre\",\n    \"className\": \"language-js\"\n  }, \"// nightwatch.conf.js\\n//...\\ncustom_commands_path: ['nightwatch/commands'],\\n//...\\n\")), mdx(\"p\", null, \"If there was no type-checking, one would be able to use \", mdx(\"inlineCode\", {\n    parentName: \"p\"\n  }, \"browser.waitForLoadScreen(5000)\"), \", but since \", mdx(\"inlineCode\", {\n    parentName: \"p\"\n  }, \"waitForLoadScreen\"), \" is not a typed method of the Nightwatch API TypeScript will display an error alerting one that waitForLoadScreen does not exist on the browser object. So in step 2, let's fix that.\"), mdx(\"h3\", {\n    \"id\": \"step-2-add-a-definition-for-your-custom-command\"\n  }, \"Step 2: Add a definition for your Custom Command\"), mdx(\"p\", null, \"In the \", mdx(\"inlineCode\", {\n    parentName: \"p\"\n  }, \"nightwatch/types\"), \" folder create a file called \", mdx(\"inlineCode\", {\n    parentName: \"p\"\n  }, \"nightwatch.d.ts\"), \". This will append your command to the existing NightwatchCustomCommands type definitions.\"), mdx(\"pre\", null, mdx(\"code\", {\n    parentName: \"pre\",\n    \"className\": \"language-ts\"\n  }, \"// nightwatch/types/nightwatch.d.ts\\ndeclare module 'nightwatch' {\\n  export interface NightwatchCustomCommands {\\n    waitForLoadScreen(maxWaitInMs: number): Awaitable<this, null>;\\n  }\\n}\\n\")), mdx(\"h3\", {\n    \"id\": \"step-3-link-the-definition-file-through-tsconfig\"\n  }, \"Step 3: Link the definition file through tsconfig\"), mdx(\"p\", null, \"Open the \", mdx(\"inlineCode\", {\n    parentName: \"p\"\n  }, \"./nightwatch/tsconfig.json\"), \" (there is one in the root project directory as well--leave that outer one alone)\"), mdx(\"pre\", null, mdx(\"code\", {\n    parentName: \"pre\",\n    \"className\": \"language-js\"\n  }, \"// nightwatch/tsconfig.json\\n\\\"compilerOptions\\\": {\\n  // excluded for brevity\\n},\\n\\\"files\\\": [\\\"/types/nightwatch.d.ts\\\"]\\n\")), mdx(\"p\", null, \"Append the files property under compilerOptions as shown with the path to the definition file. Once all three steps are complete the custom command should be available to use without any TypeScript warnings.\"), mdx(\"h2\", {\n    \"id\": \"final-thoughts\"\n  }, \"Final Thoughts\"), mdx(\"p\", null, \"The Nightwatch TypeScript implementation has matured very nicely over the past year and should continue to progress with Nightwatch 3.0 right around the corner. Stay tuned for updates on their \", mdx(\"a\", {\n    parentName: \"p\",\n    \"href\": \"https://github.com/nightwatchjs/nightwatch/releases\"\n  }, \"Nightwatch GitHub Releases\"), \" page for the latest.\"), mdx(\"p\", null, \"If you are a Nightwatch beginner be sure to watch my \", mdx(\"a\", {\n    parentName: \"p\",\n    \"href\": \"https://youtube.com/playlist?list=PLLS_Ef55N6hmkt3-JlW40GAGpXSlp8t_D\"\n  }, \"Software Testing Playlist\")), mdx(\"p\", null, \"Please share the link to this article if you enjoyed it and if you have any questions or comments please reach out through my social links below \\uD83D\\uDC47\"));\n}\n;\nMDXContent.isMDXComponent = true;"}},"pageContext":{"id":"ac2df9c1-2c46-50ff-8fcc-94118039b97a"}},"staticQueryHashes":["1961101537","2542493696"]}